package org.bambrikii.kbManager.kb2.managers.query5.q;

import java.util.LinkedHashMap;
import java.util.Map;

import org.bambrikii.kbManager.kb2.managers.query5.And;
import org.bambrikii.kbManager.kb2.managers.query5.ICriteria;
import org.bambrikii.kbManager.kb2.managers.query5.Kind;
import org.bambrikii.kbManager.kb2.managers.query5.Like;
import org.bambrikii.kbManager.kb2.managers.query5.Or;
import org.bambrikii.kbManager.kb2.managers.query5.Source;
import org.bambrikii.kbManager.kb2.model.ArtefactAsText;

import com.mysql.jdbc.StringUtils;

public class QueryBuilder {
	private static final Class<ArtefactAsText> CLASS = ArtefactAsText.class;
	private static String LINE_BREAK = "\n";
	private Map<String, Join> from = new LinkedHashMap<String, Join>();
	private String select = null;

	public synchronized ParsedQuery getQuery(ICriteria crit) {
		String where = getWhere(null, crit);
		String from = getFrom();
		return new ParsedQuery(select, from, where);
	}

	private String getFrom() {
		StringBuilder sb = new StringBuilder();
		for (String alias : from.keySet()) {
			Join join = from.get(alias);
			if (join.getTable() == null) {
				sb.append(CLASS.getSimpleName());
				select = join.getAlias();
			} else {
				sb.append(" join ").append(join.getTable()).append(".")
						.append(join.getField().getName());
			}
			sb.append(" as ").append(alias).append(LINE_BREAK);
		}
		return sb.toString();
	}

	private String getWhere(String alias, ICriteria crit) {
		if (crit instanceof And) {
			return LINE_BREAK + getAnd(alias, (And) crit) + LINE_BREAK;
		} else if (crit instanceof Or) {
			return LINE_BREAK + getOr(alias, (Or) crit) + LINE_BREAK;
		} else if (crit instanceof Like) {
			return getLike(alias, (Like) crit);
		} else if (crit instanceof Source) {
			return getSource(alias, (Source) crit);
		} else if (crit instanceof Kind) {
			return getKind(alias, (Kind) crit);
		}
		return null;
	}

	private String getAnd(String alias, And crit) {
		return "(" + getWhere(alias, crit.getCrit1()) + " and "
				+ getWhere(alias, crit.getCrit2()) + ")";
	}

	private String getOr(String alias, Or crit) {
		return "(" + getWhere(alias, crit.getCrit1()) + " or "
				+ getWhere(alias, crit.getCrit2()) + ")";
	}

	private String getLike(String alias, Like crit) {
		return alias + ".key like '" + crit.getValue() + "'";
	}

	private String getSource(String alias, Source crit) {
		String alias2 = StringUtils.isNullOrEmpty(alias) ? "s" : alias + "_s";
		from.put(alias2, new Join(alias, JoinTable.SOURCE, alias2));
		return getWhere(alias2, crit.getCrit1());
	}

	private String getKind(String alias, Kind crit) {
		String alias2 = StringUtils.isNullOrEmpty(alias) ? "s" : alias + "_k";
		from.put(alias2, new Join(alias, JoinTable.KIND, alias2));
		return getWhere(alias2, crit.getCrit1());
	}
}
